home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
a_utils
/
decomp.lha
/
decomp
/
disasm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-01-12
|
11KB
|
526 lines
/*
* Module: disasm.c
*
* Author: J. Reuter
*
* This module "disassembles" a function into pseudo-C code
* for data manipulation and pseudo-assembler code for all
* conditional test and branch instructions. It makes no
* attempt to structure the code.
*
* This disassembler is used as a fallback when the fancy
* structuring code breaks. This does not happen very often
* with PCC output. Occasionally the Unix peephole optimizer will
* combine the last bits of code for several functions, causing
* the structuring code to break.
*/
#include "defs.h"
#include "machine.h"
#include "labeltab.h"
#include "objfile.h"
#include "vartab.h"
extern char *typesuf[];
static struct operand {
int op_argval;
int op_indexed;
int op_index_rn;
int op_index_type;
char opstring[40];
} operand[6];
disasm( addr, end_addr )
address addr, end_addr;
{
struct opcode *op;
VaxOpcode ins;
address insaddr;
unsigned char mode;
int argtype, amode, argno, argval;
int rn, type;
short offset;
struct nlist *s;
char *str;
struct llb *l;
struct relocation_info *r;
/* initialize pass */
l = llb_first();
relo_first();
r = relo_next();
/* the main loop */
while ( addr < end_addr ) {
argval = 0;
while ( l->l_address < addr )
l = llb_next();
if ( l != NULL && addr == l->l_address ) {
if ( l->caselab )
printf( "C%04d:", addr );
else
printf( "G%04d:", addr );
}
ins = get_byte( addr );
addr += 1;
op = &opcode[ins];
for (argno = 0; argno < op->numargs; argno++)
operand[argno].op_indexed = FALSE;
for (argno = 0; argno < op->numargs; argno++) {
str = operand[argno].opstring;
argtype = op->argtype[argno];
if (is_branch_disp(argtype)) {
mode = 0xAF + ( (typelen(argtype) & ~T_UNSIGNED) << 4);
} else {
mode = get_byte( addr );
addr += 1;
}
while ( r != NULL && addr > r->r_address )
r = relo_next();
rn = regnm( mode );
type = typelen( argtype );
amode = addrmode(mode);
if ( r != NULL && addr == r->r_address ) {
if ( amode == LONGDISP || amode == LONGDISPDEF ) {
argval = getdisp(addr, 4, rn, amode);
addr += 4;
} else if ( amode == AUTOINC ) {
if ( rn != PC ) {
printf( "ERR: strange relo autoinc reg\n" );
} else {
/* immediate values */
switch ( type & ~T_UNSIGNED ) {
case TYPL:
argval = getdisp(addr, 4, rn, amode);
addr += 4;
break;
default:
printf( "ERR: strange relo autoinc %d\n", type );
break;
}
}
} else {
printf( "ERR: bad relo mode %d\n", amode );
}
if ( r->r_extern ) {
s = &symtab[r->r_symbolnum];
if ( s->n_type == (N_EXT+N_UNDF) ) {
if ( amode == LONGDISP || amode == LONGDISPDEF ) {
char *def;
if ( amode == LONGDISPDEF ) {
def = "*";
type |= T_POINTER;
} else {
def = "";
}
if ( rn == PC )
sprintf( str, "%s%s", def,
ext_sym( r->r_symbolnum, type, argval ) );
else
sprintf( str, "%s%s(r%02d)", def,
ext_sym( r->r_symbolnum, type, argval ),
rn );
} else if ( amode == AUTOINC ) {
sprintf( str, "%s", ext_sym( r->r_symbolnum, type,
argval ) );
} else {
printf( "ERR: ext relo mode %d\n", amode );
}
} else {
printf( "ERR: ext relo type %d\n", s->n_type );
}
} else { /* not r->r_extern */
if ( amode == LONGDISP || amode == LONGDISPDEF ) {
char *def;
if ( amode == LONGDISPDEF ) {
def = "*";
type |= T_POINTER;
} else {
def = "";
}
if ( rn == PC ) {
switch ( r->r_symbolnum ) {
case 4:
/* static function */
sprintf( str, "%s%s", def,
int_sym( argval, type, C_TEXT ) );
break;
case 5:
/* global function */
sprintf( str, "%s%s", def,
int_sym( argval, type, C_TEXT ) );
break;
case 6:
/* static data, const, string */
sprintf( str, "%s%s", def,
int_sym( argval, type, C_DATA ) );
break;
case 7:
/* global data, const, string */
sprintf( str, "%s%s", def,
int_sym( argval, type, C_DATA ) );
break;
case 8:
/* bss */
sprintf( str, "%s%s", def,
int_sym( argval, type, C_BSS ) );
break;
default:
printf( "ERR: bad relo symbolnum %d\n",
r->r_symbolnum );
break;
}
} else {
/* other registers? */
sprintf( str, "%s%d(r%02d)", def, argval, rn );
printf( "\targ %d int longdisp sym#%d pcrel %d len %d reg %d\n",
argno, r->r_symbolnum, r->r_pcrel, r->r_length, rn );
}
} else if ( amode == AUTOINC ) {
switch ( r->r_symbolnum ) {
case 6:
/* static data */
sprintf( str, "%s", int_sym( argval, type, C_DATA ) );
break;
case 8:
/* static bss */
sprintf( str, "%s", int_sym( argval, type, C_BSS ) );
break;
default:
printf( "ERR: auto relo symnum %d\n", r->r_symbolnum );
break;
}
} else {
printf( "ERR: int relo mode %d\n", amode );
}
}
} else { /* no relo info */
switch (amode) {
case LITSHORT:
case LITUPTO31:
case LITUPTO47:
case LITUPTO63:
if ( type == TYPF || type == TYPD )
sprintf( str, "%s", fltimm[mode] );
else
sprintf( str, "%d", mode );
argval = mode;
break;
case INDEX:
operand[argno].op_indexed = TRUE;
operand[argno].op_index_rn = rn;
operand[argno].op_index_type = T_LONG;
argno--;
break;
case REG:
sprintf( str, "%s", reg_sym( rn, type ) );
break;
case REGDEF:
sprintf( str, "*%s", reg_sym( rn, type | T_POINTER ) );
break;
case AUTODEC:
if ( rn == SP )
sprintf( str, "@arg@" );
else
sprintf( str, "*(--%s)",
reg_sym( rn, type | T_POINTER) );
break;
case AUTOINC:
if ( rn != PC ) {
sprintf( str, "*%s++",
reg_sym( rn, type | T_POINTER ) );
} else {
/* immediate values */
switch ( type & ~T_UNSIGNED ) {
case TYPB:
argval = getdisp(addr, 1, rn, amode);
addr += 1;
break;
case TYPW:
argval = getdisp(addr, 2, rn, amode);
addr += 2;
break;
case TYPL:
argval = getdisp(addr, 4, rn, amode);
addr += 4;
break;
default:
printf( "ERR: strange-autoinc %d\n", type );
break;
}
sprintf( str, "%d", argval );
}
break;
case AUTOINCDEF:
if ( rn == PC ) {
/* immediate deferred */
argval = getdisp(addr, 4, rn, amode);
addr += 4;
sprintf( str, "*%d", argval );
} else {
sprintf( str, "**(%s++)",
reg_sym( rn, type | T_POINTER ) );
}
break;
case BYTEDISP:
argval = getdisp(addr, 1, rn, amode);
regdisp( rn, argval, type, FALSE, str );
addr += 1;
break;
case BYTEDISPDEF:
;
argval = getdisp(addr, 1, rn, amode);
regdisp( rn, argval, type, TRUE, str );
addr += 1;
break;
case WORDDISP:
argval = getdisp(addr, 2, rn, amode);
regdisp( rn, argval, type, FALSE, str );
addr += 2;
break;
case WORDDISPDEF:
;
argval = getdisp(addr, 2, rn, amode);
regdisp( rn, argval, type, TRUE, str );
addr += 2;
break;
case LONGDISP:
argval = getdisp(addr, 4, rn, amode);
regdisp( rn, argval, type, FALSE, str );
addr += 4;
break;
case LONGDISPDEF:
;
argval = getdisp(addr, 4, rn, amode);
regdisp( rn, argval, type, TRUE, str );
addr += 4;
break;
}
}
operand[argno].op_argval = argval;
}
/* print the decompiled instruction */
#define doindex( i ) if ( operand[i].op_indexed ) printf( "[%s]", \
reg_sym( operand[i].op_index_rn, operand[i].op_index_type ) )
switch( op->coptype ) {
case MACRO: /* print macro code */
case COMP:
case TEST:
case BBRANCH:
case CBRANCH:
printf( "\t%s\t", op->cop1 );
for ( argno = 0; argno < op->numargs; argno++ ) {
if ( argno != 0 )
printf( "," );
printf( "%s", operand[argno].opstring );
doindex(argno);
}
if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) {
insaddr = addr;
for (argno = 0; argno <= argval; argno++) {
offset = get_word( addr );
addr += 2;
printf( "\n\t\tC%04d", offset+insaddr );
}
}
printf( "\n" );
break;
case A1OPA0:
printf( "\t%s", operand[1].opstring );
doindex(1);
printf( "%s", op->cop1 );
printf( "%s", operand[0].opstring );
doindex(0);
printf( ";\n" );
break;
case A2EQ1OP0:
printf( "\t%s", operand[2].opstring );
doindex(2);
printf( " = %s", operand[1].opstring );
doindex(1);
printf( "%s", op->cop1 );
printf( "%s", operand[0].opstring );
doindex(0);
printf( ";\n" );
break;
case A0OP:
printf( "\t%s", operand[0].opstring );
doindex(0);
printf( "%s;\n", op->cop1 );
break;
case OPONLY:
printf( "\t%s;\n", op->cop1 );
break;
case CALLS:
printf( "\t@val@ = %s", operand[1].opstring );
doindex(1);
printf( "( @%s args@ );\n", operand[0].opstring );
break;
case PUSH:
printf( "\t@arg@ = %s", operand[0].opstring );
doindex(0);
printf( ";\n" );
break;
case PUSHA:
printf( "\t@arg@ = &%s", operand[0].opstring );
doindex(0);
printf( ";\n" );
break;
case EXTZV:
printf( "\t%s", operand[3].opstring );
doindex(3);
printf( " = " );
if ( operand[0].op_argval != 0 ) {
printf( "( %s", operand[2].opstring );
doindex(2);
printf( " >> %d )", operand[0].op_argval );
} else {
printf( "%s", operand[2].opstring );
doindex(2);
}
if ( operand[1].op_argval != 32 )
printf( " & 0x%x;\n",
0x7fffffff >> ( 31 - operand[1].op_argval ) );
else
printf( ";\n" );
}
}
}
/*
* Print the displacement of an instruction that uses displacement
* addressing.
*/
static int
getdisp(addr, nbytes, rn, mode)
address addr;
int nbytes;
int rn;
int mode;
{
int argval;
switch (nbytes) {
case 1:
argval = get_byte( addr );
break;
case 2:
argval = get_word( addr );
break;
case 4:
argval = get_long( addr );
break;
}
if (rn == PC && mode >= BYTEDISP) {
argval += addr + nbytes;
}
return argval;
}
static
regdisp( rn, offset, type, defr, str )
int rn, offset, type, defr;
char *str;
{
char *ds;
if ( defr )
ds = "*";
else
ds = "";
switch ( rn ) {
/* arguments */
case AP:
if ( offset < 0 )
printf( "ERR: bad argument offset %d\n", offset );
else
sprintf( str, "%s%s", ds, arg_sym( offset, type ) );
break;
/* locals */
case FP:
if ( offset > 0 )
printf( "bad local offset %d\n", offset );
else
sprintf( str, "%s%s", ds, loc_sym( -offset, type ) );
break;
case PC:
if ( defr )
printf( "ERR: PC deferred\n" );
sprintf( str, "G%04d", offset );
break;
/* everything else */
default:
sprintf( str, "%s%s->O%03d%s", ds, reg_sym( rn, type | T_POINTER ),
offset, typesuf[ type ] );
break;
}
}